package comp353Games;

import java.awt.Container;
import java.util.Arrays;

/**
 * SnortCol describes a game of SnortCol. More information about this game is
 * available here: http://en.wikipedia.org/wiki/Snort
 *
 * @author Tyler Radley, Andre Harvey, Deanna Fink
 * @version 4/30/12
 */
public class SnortCol implements GameModel {

    //The error message to be printed if an error arises
    private String errorMessage;
    
    //An array containing whether the listed games are Snort.  Used to differentiate between snort and Col.
    private boolean isSnort;
    
    //An array of sections of connected nodes
    private int[][] rows;
    
    //constants
    /**
     * A constant representing Player 1
     */
    public static final int PLAYER_ONE = 1;
    /**
     * A constant representing Player 2
     */
    public static final int PLAYER_TWO = 2;

    /**
     * Constructor for a default basic game with four rows of sizes 3, 5, and 7
     */
    public SnortCol(boolean isSnort) {
        this.isSnort = isSnort;
        // initialize instance variables
        rows = new int[][]{new int[3], new int[5], new int[7], new int[9]};
    }

    /**
     * Constructor for a game of SnortCol in which the user can specify the size
     * of rows
     *
     * @param rowSizes An array containing the size of each heap
     */
    public SnortCol(int[][] rows, boolean isSnort) {
        this.isSnort = isSnort;
        System.out.println("we are in the constructor!");
        this.errorMessage = "";
        if (rows.length < 1) {
            this.errorMessage = "Error. Number of rows invalid";
            System.out.println("this didn't work!");
        } else {
            this.rows = rows;
        }
    }

    @Override
    public String getName() {
        if (isSnort) {
            return "Snort";
        } else {
            return "Col";
        }
    }

    @Override
    public SnortCol getNewGame() {
        return new SnortCol(isSnort);
    }

    @Override
    public SnortColDisplay getDisplay(GameModel game) {
        return new SnortColDisplay(game);
    }

    /**
     * Returns the array of node values
     *
     * @return The array of node values
     */
    public int[][] getRows() {
        return rows;
    }

    /**
     * Returns the current error message
     *
     * @return The current error message
     */
    public String getErrorMessage() {
        return this.errorMessage;
    }

    /**
     * Returns a hash code for this game.
     *
     * @return //Returns a hash code for this game.
     */
    public int hashCode() {
        int code = 0;
        for (int i = 0; i < this.rows.length; i++) {
            code += (this.rows[i].length + 1) * Math.pow(3, i);
        }
        return code;
    }

    /**
     * Returns whether this equals another SnortCol game.
     *
     * @param obj Another object with which our current game is compared to.
     * @return Returns whether this equals another SnortCol game (other).
     *
     */
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final SnortCol other = (SnortCol) obj;
        if (!Arrays.deepEquals(this.rows, other.rows)) {
            return false;
        }
        return true;
    }

    /**
     * Checks whether the selected cell exists and is a valid move for the
     * current player.
     *
     * @param rowIndex The chosen row.
     * @param nodeIndex The chosen cell.
     * @param player The code identifying the current player.
     * @param displayErrors Denotes whether the function should display errors
     * or not.
     *
     * @return Whether the selected cell exists and is a valid move for the
     * current player.
     */
    public boolean validNode(int nodeIndex, int rowIndex, int player,
            boolean displayErrors) {
        System.out.print(isSnort);
        int invalidAdjacent;
        this.errorMessage = "";
        if (isSnort) {
            if (player == PLAYER_ONE) {
                invalidAdjacent = PLAYER_TWO;
            } else {
                invalidAdjacent = PLAYER_ONE;
            }
        } else {
            if (player == PLAYER_TWO) {
                invalidAdjacent = PLAYER_TWO;
            } else {
                invalidAdjacent = PLAYER_ONE;
            }
        }
        if (nodeIndex < 0 || nodeIndex >= this.rows[rowIndex].length) {
            if (displayErrors) {
                this.errorMessage = "Invalid Index";
            }
            return false;
        }
        System.out.println(this.rows[rowIndex][nodeIndex]);
        if (this.rows[rowIndex][nodeIndex] != 0) {
            if (displayErrors) {
                this.errorMessage = "This node has already been colored in!";
            }
            return false;
        } else {
            if (nodeIndex > 0) {
                if (this.rows[rowIndex][nodeIndex - 1] == invalidAdjacent) {
                    if (displayErrors && isSnort) {
                        this.errorMessage = "You can't pick a node adjacent to "
                                + "the other player's node";
                    }
                    if (displayErrors && !isSnort) {
                        this.errorMessage = "You can't pick a node adjacent to "
                                + "your node";
                    }
                    return false;
                }
            }
            if (nodeIndex < (this.rows[rowIndex].length - 1)) {
                if (this.rows[rowIndex][nodeIndex + 1] == invalidAdjacent) {
                    if (displayErrors && isSnort) {
                        this.errorMessage = "You can't pick a node adjacent to "
                                + "the other player's node";
                    }
                    if (displayErrors && !isSnort) {
                        this.errorMessage = "You can't pick a node adjacent to "
                                + "your node";
                    }
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Checks whether the selected row exists and has valid moves for the
     * current player.
     *
     * @param rowIndex The chosen row
     * @param player The code identifying the current player.
     * @param displayErrors Denotes whether the function should display errors
     * or not.
     *
     * @return Whether the selected row exists and has valid moves for the
     * current player.
     */
    public boolean validRow(int rowIndex, int player, boolean displayErrors) {
        if (rowIndex < 0 || rowIndex >= this.rows.length) {
            return false;
        } else {
            for (int i = 0; i < this.rows[rowIndex].length; i++) {
                if (validNode(i, rowIndex, player, displayErrors)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean hasMovesRemaining(int player) {
        boolean displayErrors = false;
        for (int i = 0; i < rows.length; i++) {
            if (validRow(i, player, displayErrors)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Updates the game for the next move
     *
     * @param player The current player
     * @param row The chosen row.
     * @param cell The chosen cell.
     * @return A new game updated with all the moves made.
     */
    public SnortCol move(int row, int cell, int player) {

        SnortCol game2 = new SnortCol(isSnort);

        game2.rows = this.rows;
        game2.rows[row][cell] = player;

        for (int i = 0; i < game2.rows.length; i++) {
            for (int j = 0; j < game2.rows[i].length; j++) {
                System.out.print(" " + this.rows[i][j]);
            }
            System.out.print("\n");
        }

        return game2;
    }

    /**
     * Returns a string version of this.
     *
     * @param indent The indentation between the edge of the window and the
     * text.
     * @return A string version of the game indented from the margin.
     */
    public String toString(String indent) {
        StringBuilder stringBuffer = new StringBuilder();
        stringBuffer.append(indent).append("Snort\n");
        stringBuffer.append(indent).append("|");
        for (int i = 0; i < this.rows.length; i++) {
            for (int j = 0; j < rows[i].length; i++) {
                stringBuffer.append(" ");
                if (this.rows[i][j] == -1) {
                    stringBuffer.append("B");
                } else if (this.rows[i][j] == 0) {
                    stringBuffer.append(" ");
                } else if (this.rows[i][j] == 1) {
                    stringBuffer.append("R");
                } else {
                    //this case should never happen.  If we reach this,
                    //  something went logically wrong!
                    //stringBuffer.append(rows[i][j]);
                }
            }
            stringBuffer.append(" |");
        }
        stringBuffer.append("\n");
        return stringBuffer.toString();
    }

    @Override
    public String toString() {
        return this.toString("");
    }

    @Override
    public boolean validMove(int[] gamePress, int[] gameRelease,
            int[] gameClick, int currentPlayer) {
        return validNode(gameClick[1], gameClick[0], currentPlayer, true);
    }

    @Override
    public GameModel updateGame(int[] gamePress, int[] gameRelease, int[] gameClick, int currentPlayer) {
        this.rows[gameClick[0]][gameClick[1]] = currentPlayer;
        System.out.println(this.rows[gameClick[0]][gameClick[1]]);
        return new SnortCol(this.rows, isSnort);
    }

    @Override
    public int[] mouseClickedHandler(int xPosition, int yPosition, int currentPlayer) {
        int[] xBounds = new int[100];
        int[] yBounds = new int[100];
        int[] indexArray = new int[2];

        // Check if the click was inside the rectangle area.
        for (int i = 0; i < this.rows.length; i++) {
            System.out.println("snort" + xPosition + "," + yPosition);
            for (int j = 0; j < this.rows[i].length; j++) {
                xBounds[j] = j * 30 + 48;
                yBounds[i] = i * 35 + 47;
                if ((xPosition > xBounds[j] && xPosition < xBounds[j] + 20)
                        && yPosition > yBounds[i]
                        && yPosition < yBounds[i] + 20) {

                    indexArray[0] = (int) (Math.floor((yPosition - 47) / 35));
                    indexArray[1] = (int) (Math.floor((xPosition - 48) / 30));
                    System.out.println(indexArray[0] + "," + indexArray[1]);
                    return indexArray;
                }
            }
        }
        indexArray[0] = -1;
        indexArray[1] = -1;
        return indexArray;


    }

    @Override
    public int[] mousePressedHandler(int xPosition, int yPosition) {
        return null;
    }

    @Override
    public int[] mouseReleasedHandler(int xPosition, int yPosition) {
        return null;
    }

    @Override
    public String[] getInstructions(int currentPlayer) {
        String snortOrCol;
        String[] instructions = new String[3];
        if (currentPlayer == 1) {
            instructions[2] = "BLUE";
        } else {
            instructions[2] = "RED";
        }

        if (isSnort) {
            snortOrCol = "an enemy's circle";
            instructions[0] = "Welcome to Snort!  ";
        } else {
            snortOrCol = "another one of your circles";
            instructions[0] = "Welcome to Col!  ";
        }
        instructions[1] = "It's now " + instructions[2] + "'s turn.  Click on an empty circle to claim it.  You may not claim a circle adjacent to " + snortOrCol + " on the same row.";

        return instructions;
    }

    @Override
    public String save() {
        String saveText = "<";

        if (isSnort) {
            saveText += "Snort>\n";
        } else {
            saveText += "Col>\n";
        }
        saveText += "<rows>\n";
        saveText += rows.length + "x";
        for (int i = 0; i < rows.length; i++) {
            saveText += rows[i].length + ".";
        }
        saveText += "\n";

        for (int i = 0; i < rows.length; i++) {
            for (int j = 0; j < rows[i].length; j++) {
                saveText += rows[i][j] + ".";
            }
            saveText += "\n";
        }

        saveText += "</rows>\n";
        if (isSnort) {
            saveText += "</Snort>";
        } else {
            saveText += "</Col>";
        }
        return saveText;
    }

    @Override
    public SnortCol load(String fileString) {
        int index;
        if (isSnort) {
            index = 13;
        } else {
            index = 11;
        }

        String lengthString = "";

        while (fileString.substring(index, index + 1).equals("x") == false) {
            lengthString += fileString.charAt(index);
            index++;
        }
        index++;

        int lengthValue = Integer.parseInt(lengthString);
        int[][] newRows = new int[lengthValue][];
        for (int i = 0; i < lengthValue; i++) {
            String currentRowSize = "";
            while (fileString.substring(index, index + 1).equals(".") == false) {
                currentRowSize += fileString.charAt(index);
                index++;
            }
            System.out.println(currentRowSize);

            newRows[i] = new int[Integer.parseInt(currentRowSize)];
            index++;
        }
        for (int i = 0; i < lengthValue; i++) {
            for (int j = 0; j < newRows[i].length; j++) {
                String currentValue = "";
                while (fileString.substring(index, index + 1).equals(".") == false) {
                    currentValue += fileString.charAt(index);
                    index++;
                }
                newRows[i][j] = Integer.parseInt(currentValue);
                index++;
            }
        }
        System.out.println(newRows);
        return new SnortCol(newRows, this.isSnort);
    }
}

